import re

from Problems.models import Problem
from Problems.serializers import ProblemDetailSerializer
from Robots.BaseRobot import BaseRobot
from Robots.Exceptions import AuthFailed, SubmitProblemFailed, RequestFailed, RegexError
from Robots.models import RemoteOJ


class HDURobot(BaseRobot):
    def __init__(self, cookies=None, token="", username=None, password=None):
        super().__init__(cookies, token, username, password)
        self.session = None

        if username is not None:
            self.login(username, password)

    def save(self):
        return {"cookies": self.cookies, "token": self.token}

    def check_url(self, url):
        regex = r"^https://acm.hdu.edu.cn/showproblem.php\?pid=\d{4}$"
        return re.compile(regex).match(url) is not None

    def release(self):
        if self.username is not None:
            # 找到 username 对应的账户并把 is_active 字段修改为 true,并保存
            from Robots.models.RobotAccount import RobotAccount
            RobotAccount.objects.filter(username=self.username, password=self.password,
                                        remote_oj__name="HDU").update(is_active=True)

    def login(self, username, password):
        r = self.post("http://acm.hdu.edu.cn/userloginex.php?action=login",
                      data={"username": username,
                            "userpass": password,
                            "login": "Sign In"},
                      headers={"Content-Type": "application/x-www-form-urlencoded",
                               "Referer": "http://acm.hdu.edu.cn/"})
        # 登陆成功会重定向到首页,否则200返回错误页面
        if r.status_code != 302:
            raise AuthFailed("Failed to login Hduoj")

        self.cookies = dict(r.cookies)

    @property
    def is_logged_in(self):

        r = self.get("http://acm.hdu.edu.cn/control_panel.php", cookies=self.cookies)
        # 登录状态是200,否则302到登陆页面
        return r.status_code == 200

    def get_problem(self, problem_id):
        problem_id = re.compile(r"\d{4}").search(problem_id).group()

        flg = 0
        try:
            problem = Problem.objects.get(remote_id=problem_id, remote_oj__name="HDU")
        except Problem.DoesNotExist:
            problem = None
        else:
            flg = 1

        if problem is not None and problem.content is not None:
            return ProblemDetailSerializer(problem).data

        url = f"https://acm.hdu.edu.cn/showproblem.php?pid={problem_id}"
        if not self.check_url(url):
            raise RequestFailed("Invaild Hduoj url")
        regex = {"title": r"<h1 style='color:#1A5CC8'>(.*)</h1>",
                 "time_limit": r"Time Limit:\s*[\d]*/([\d]*)\s*MS",
                 "memory_limit": r"Memory Limit:\s*[\d]*/([\d]*)\s*K",
                 "description": r"Problem Description</div>\s*<div class=panel_content>([\s\S]*?)</div>",
                 "input_description": r"Input</div>\s*<div class=panel_content>([\s\S]*?)</div>",
                 "output_description": r"Output</div>\s*<div class=panel_content>([\s\S]*?)</div>",
                 "hint": r"Hint(?:[\s\S]*?Hint[\s\S]*?</i>|</i>\s*</div>)([\s\S]*?)</div>",
                 "samples": r'Courier New,Courier,monospace;">([\s\S]*?)(?:<div|</div>)'}
        problem_id = re.compile(r"\d{4}").search(url).group()
        data = self._regex_page(url, regex)
        data["is_spj"] = False
        data["remote_oj"] = RemoteOJ.objects.get(name="HDU")
        data["remote_id"] = problem_id
        data_content = {}
        data_content["samples"] = data.pop("samples")
        data_content["input_description"] = data.pop("input_description")
        data_content["output_description"] = data.pop("output_description")
        data_content["hint"] = data.pop("hint")
        data_content["description"] = data.pop("description")
        data["content"] = data_content

        if flg == 0:  # 数据库中没有，直接保存
            serializer = ProblemDetailSerializer(data=data)
            if serializer.is_valid():
                serializer.save()
                pass
        else:
            # 数据库中存在，需要更新,将 problem 更新为 problem 2
            serializer = ProblemDetailSerializer(problem, data=data)
            if serializer.is_valid():
                serializer.save()

        return serializer.data

    def submit(self, language, code, origin_id):
        self.login(self.username, self.password)
        print(origin_id)
        submit_url = "https://acm.hdu.edu.cn/submit.php?action=submit"
        code = code.encode("gb2312")
        if "C" in language or "c" in language:
            language = "0"
        else:
            language = "5"

        r = self.post(submit_url, data={"check": "0", "problemid": origin_id,
                                        "language": language,
                                        "usercode": code},
                      cookies=self.cookies,
                      headers={"Content-Type": "application/x-www-form-urlencoded",
                               "Referer": submit_url})

        if r.status_code != 302:
            raise SubmitProblemFailed("Failed to submit problem, url: %s, status code %d" % (submit_url, r.status_code))

        status_url = r"http://acm.hdu.edu.cn/status.php?&user=" + self.username
        r = self.get(status_url,
                     headers={"Refer": status_url})
        self.check_status_code(r)

        data = re.compile(r"(\d+)</td><td>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:[\s\S]*?)>"
                          r"<font[\s\S]*?>(.*?)</font>[\s\S]*?(\d*)MS</td><td>(\d*)K").findall(r.text)

        submission_id = data[0][0]

        return submission_id

    def _regex_page(self, url, regex):
        r = self.get(url)
        self.check_status_code(r)
        data = {}
        for k, v in regex.items():
            items = re.compile(v).findall(r.text)
            if not items:
                if k == "spj":
                    data[k] = False
                elif k == "hint":
                    data["hint"] = None
                else:
                    raise RegexError("No such data")
            if k == "samples":
                data[k] = [{"input": items[0], "output": items[1]}]
            elif items:
                if k == "spj":
                    data[k] = True
                else:
                    data[k] = self._clean_html(items[0])
        data["memory_limit"] = "{}MB".format(int(data["memory_limit"]) // 1024)
        data["time_limit"] = "{}s".format(int(data["time_limit"]) // 1000)

        return data

    def get_result(self, submission_id, username=None, contestId=None):
        status_url = f"https://acm.hdu.edu.cn/status.php?first={submission_id}"
        r = self.get(status_url,
                     headers={"Refer": status_url})
        self.check_status_code(r)

        data = re.compile(r"(\d+)</td><td>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:[\s\S]*?)>"
                          r"<font[\s\S]*?>(.*?)</font>[\s\S]*?(\d*)MS</td><td>(\d*)K").findall(r.text)

        res = data[0][1]
        if data[0][2]:
            cpu_time = "{}ms".format(int(data[0][2]))
        else:
            cpu_time = None

        if data[0][3]:
            memory = "{}k".format(int(data[0][3]))
        else:
            memory = None

        return {
            "remote_verdict": res,
            "time_cost": cpu_time,
            "memory_cost": memory
        }

    def __str__(self):
        if self.username:
            return f"HDU机器人: {self.username}"
        return "HDU匿名机器人"
